<?php

/**
 * Pheme adapter for Tumblr syntax
 *
 * @author Sandu Lungu <sandu@lungu.info>
 * @copyright 2010 Sandu Lungu
 * @filesource
 * @license http://www.gnu.org/licenses/gpl.html GPL3
 * @link https://www.ohloh.net/p/pheme
 * @package Pheme
 * @subpackage Tumblr
 */

require_once (dirname(__FILE__).'/parser.php');

/**
 * Generic parser class. Uses a syntax compatible with Tumblr's custom templating engine's.
 *
 * The constructor takes any number of parameters, that are assigned to the $_params property
 */
class TumblrParser extends PhemeParser {
    protected $_preg = '!{(out:)?([A-Za-z][A-Za-z0-9]*)}|{block:([A-Za-z][A-Za-z0-9]*)}(.*?){/block:\\3}!';

    /**
     * Class constructor (adapted to tumbl like syntax)
     *
     * @param array $vars Associative array of blocks, templated blocks and variables
     *      (note that all variable declarations start with '$')
     * @param array $options Custom options
     */
    public function __construct($rules = array(), $options = array()) {
        $this->options = array_merge($this->options, $options);

        foreach ($rules as $name => $value) {
            if (strpos($name, 'block:') !== 0) {
            // variable
                $this->vars[$name] = $value;
            }
            else {
                $name = substr($name, 6);
                if (is_string($value)) {
                // block template
                    $this->templates[$name] = $value;
                    $this->blocks[$name] = new SilentParser();
                }
                else {
                // block
                    $this->blocks[$name] = $value;
                }
            }
        }
    }

    protected function _pregCallback($matches) {
        if (!empty($matches[2])) {
        // variable
            return !empty($matches[1]) ?
            $this->_getTemplate(substr($matches[2], 1)) :
            $this->_getVar(substr($matches[2], 1));
        } else {
        // block
            return $this->_getBlock($matches[3])->parse($matches[4], $matches[3]);
        }
    }
}

/**
 * Useful for subtemplates, like blocks or interface elements.
 *
 * The constructor takes any number of parameters, that are assigned to the $_params property
 */
class TumblrSubParser extends TumblrParser {
    protected $_params = null;

    public function __construct() {
        $this->_params = func_get_args();
        parent::__construct(array_shift($this->_params), array_shift($this->_params));
    }
}

/**
 * Copies block text to parent parser's vars array and silently returns
 */
class TumblrLoopParser extends TumblrSubParser {
    public $options = array('separator' => "\n");

    public function parse($html, $blockName = 'document', $blockParams = null) {
        $items = array();
        // the cycle itself. We use $this->_params[0], stored by the class constructor
        foreach ($this->_params[0] as $vars) {
            $items[] = $this->_parseItem($html, $vars, $blockName, $blockParams);
        }
        return implode($this->options['separator'], $items);
    }

    /**
     * Subtemplate parsing with custom vars set
     *
     * @param string $html
     * @param array $vars Associativea array of vars (strings)
     * @param string $blockName
     * @param array $blockParams
     * @return string
     */
    protected function _parseItem($html, $vars, $blockName = 'document', $blockParams = null) {
        $this->vars = $vars;
        return parent::parse($html, $blockName, $blockParams);
    }
}

/**
 * Copies block text to parent parser's vars array and silently returns
 */
class TumblrTemplateParser extends TumblrParser {
    public function parse($html, $blockName = 'document') {
        self::$_stack[count(self::$_stack) - 1]->templates[$blockName] = $html;
    }
}
